<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <meta name="keywords" content="Hexo Theme Keep">
    <meta name="description" content="Hexo Theme Keep">
    <meta name="author" content="aaton">
    
    <title>
        
            浏览器存储 |
        
        aaton&#39;s study notes
    </title>
    
<link rel="stylesheet" href="/css/style.css">

    <link rel="shortcut icon" href="/images/logo.svg">
    
<link rel="stylesheet" href="/font/css/fontawesome.min.css">

    
<link rel="stylesheet" href="/font/css/regular.min.css">

    
<link rel="stylesheet" href="/font/css/solid.min.css">

    
<link rel="stylesheet" href="/font/css/brands.min.css">

    <script id="hexo-configurations">
    let KEEP = window.KEEP || {}
    KEEP.hexo_config = {"hostname":"example.com","root":"/","language":"en"}
    KEEP.theme_config = {"toc":{"enable":false,"number":false,"expand_all":false,"init_open":false},"style":{"primary_color":"#0066cc","logo":"/images/logo.svg","favicon":"/images/logo.svg","avatar":"/images/avatar.svg","font_size":null,"font_family":null,"hover":{"shadow":false,"scale":false},"first_screen":{"enable":true,"header_transparent":true,"background_img":"/images/bg.svg","description":"Keep writing and Keep loving.","font_color":null,"hitokoto":true},"scroll":{"progress_bar":false,"percent":false}},"local_search":{"enable":false,"preload":false},"code_copy":{},"code_block":{"tools":{"enable":true,"style":"default"},"highlight_theme":"default"},"side_tools":{},"pjax":{"enable":false},"lazyload":{"enable":false},"comment":{"enable":false,"use":"valine","valine":{"appid":null,"appkey":null,"server_urls":null,"placeholder":null},"gitalk":{"github_id":null,"github_admins":null,"repository":null,"client_id":null,"client_secret":null,"proxy":null},"twikoo":{"env_id":null,"region":null,"version":"1.6.8"},"waline":{"server_url":null,"reaction":false,"version":2}},"post":{"author_label":{"enable":true,"auto":true,"custom_label_list":["Trainee","Engineer","Architect"]},"word_count":{"enable":true,"wordcount":true,"min2read":true},"img_align":"left","copyright_info":false},"version":"3.6.1"}
    KEEP.language_ago = {"second":"%s seconds ago","minute":"%s minutes ago","hour":"%s hours ago","day":"%s days ago","week":"%s weeks ago","month":"%s months ago","year":"%s years ago"}
    KEEP.language_code_block = {"copy":"Copy code","copied":"Copied","fold":"Fold code block","folded":"Folded"}
    KEEP.language_copy_copyright = {"copy":"Copy copyright info","copied":"Copied","title":"Original article title","author":"Original article author","link":"Original article link"}
  </script>
<meta name="generator" content="Hexo 6.3.0"></head>


<body>
<div class="progress-bar-container">
    

    
</div>


<main class="page-container">

    

    <div class="page-main-content">

        <div class="page-main-content-top">
            
<header class="header-wrapper">

    <div class="header-content">
        <div class="left">
            
                <a class="logo-image" href="/">
                    <img src="/images/logo.svg">
                </a>
            
            <a class="logo-title" href="/">
               aaton&#39;s study notes
            </a>
        </div>

        <div class="right">
            <div class="pc">
                <ul class="menu-list">
                    
                        <li class="menu-item">
                            <a class=""
                               href="/"
                            >
                                HOME
                            </a>
                        </li>
                    
                        <li class="menu-item">
                            <a class=""
                               href="/archives"
                            >
                                ARCHIVES
                            </a>
                        </li>
                    
                        <li class="menu-item">
                            <a class=""
                               href="/tags"
                            >
                                TAGS
                            </a>
                        </li>
                    
                        <li class="menu-item">
                            <a class=""
                               href="/categories"
                            >
                                CATEGORIES
                            </a>
                        </li>
                    
                        <li class="menu-item">
                            <a class=""
                               href="/about"
                            >
                                ABOUT
                            </a>
                        </li>
                    
                    
                </ul>
            </div>
            <div class="mobile">
                
                <div class="icon-item menu-bar">
                    <div class="menu-bar-middle"></div>
                </div>
            </div>
        </div>
    </div>

    <div class="header-drawer">
        <ul class="drawer-menu-list">
            
                <li class="drawer-menu-item flex-center">
                    <a class=""
                       href="/">HOME</a>
                </li>
            
                <li class="drawer-menu-item flex-center">
                    <a class=""
                       href="/archives">ARCHIVES</a>
                </li>
            
                <li class="drawer-menu-item flex-center">
                    <a class=""
                       href="/tags">TAGS</a>
                </li>
            
                <li class="drawer-menu-item flex-center">
                    <a class=""
                       href="/categories">CATEGORIES</a>
                </li>
            
                <li class="drawer-menu-item flex-center">
                    <a class=""
                       href="/about">ABOUT</a>
                </li>
            
        </ul>
    </div>

    <div class="window-mask"></div>

</header>


        </div>

        <div class="page-main-content-middle">

            <div class="main-content">

                
                    <div class="fade-in-down-animation">
    <div class="post-page-container">
        <div class="article-content-container">

            <div class="article-title">
                <span class="title-hover-animation">浏览器存储</span>
            </div>

            
                <div class="article-header">
                    <div class="avatar">
                        <img src="/images/avatar.svg">
                    </div>
                    <div class="info">
                        <div class="author">
                            <span class="name">aaton</span>
                            
                                <span class="author-label">Lv3</span>
                            
                        </div>
                        <div class="meta-info">
                            
<div class="article-meta-info">
    <span class="article-date article-meta-item">
        
            <i class="fa-regular fa-calendar-plus"></i>&nbsp;
        
        <span class="pc">2023-12-18 09:06:45</span>
        <span class="mobile">2023-12-18 09:06</span>
    </span>
    
        <span class="article-update-date article-meta-item">
        <i class="fas fa-file-pen"></i>&nbsp;
        <span class="pc">2024-04-16 10:07:21</span>
    </span>
    
    
        <span class="article-categories article-meta-item">
            <i class="fas fa-folder"></i>&nbsp;
            <ul>
                
                    <li>
                        <a href="/categories/%E6%B5%8F%E8%A7%88%E5%99%A8/">浏览器</a>&nbsp;
                    </li>
                
            </ul>
        </span>
    
    
        <span class="article-tags article-meta-item">
            <i class="fas fa-tags"></i>&nbsp;
            <ul>
                
                    <li>
                        <a href="/tags/%E6%B5%8F%E8%A7%88%E5%99%A8/">浏览器</a>&nbsp;
                    </li>
                
                    <li>
                        | <a href="/tags/%E6%95%B0%E6%8D%AE%E5%AD%98%E5%82%A8/">数据存储</a>&nbsp;
                    </li>
                
                    <li>
                        | <a href="/tags/sessionStorage/">sessionStorage</a>&nbsp;
                    </li>
                
                    <li>
                        | <a href="/tags/localStorage/">localStorage</a>&nbsp;
                    </li>
                
                    <li>
                        | <a href="/tags/cookie/">cookie</a>&nbsp;
                    </li>
                
                    <li>
                        | <a href="/tags/IndexedDB/">IndexedDB</a>&nbsp;
                    </li>
                
                    <li>
                        | <a href="/tags/web-SQL/">web SQL</a>&nbsp;
                    </li>
                
            </ul>
        </span>
    

    
    
        <span class="article-wordcount article-meta-item">
            <i class="fas fa-file-word"></i>&nbsp;<span>3.6k Words</span>
        </span>
    
    
        <span class="article-min2read article-meta-item">
            <i class="fas fa-clock"></i>&nbsp;<span>14 Mins</span>
        </span>
    
    
        <span class="article-pv article-meta-item">
            <i class="fas fa-eye"></i>&nbsp;<span id="busuanzi_value_page_pv"></span>
        </span>
    
</div>

                        </div>
                    </div>
                </div>
            

            <div class="article-content keep-markdown-body">
                

                <p><img src="https://cn.bing.com/th?id=OHR.LofotenRorbu_ZH-CN7790383976_1920x1080.webp&qlt=50" alt="bing.com-传统钓鱼小屋，斯沃尔韦尔，罗弗敦群岛，挪威" title="bing.com-传统钓鱼小屋，斯沃尔韦尔，罗弗敦群岛，挪威"></p>
<p>浏览器存储的几种方式及各自的使用方式、优缺点。</p>
<span id="more"></span>

<hr>
<p>前端的本地存储，就是将一些数据存储在浏览器本地。这些数据可能是从服务器端获取到的数据，也可能是在多个页面中需要频繁使用到的数据。</p>
<p>比如，在一个项目中，我们需要经常使用到用户的基本信息，如果没有本地存储的话，我们不得不每次需要时去请求接口；但是有了本地存储，我们就可以在第一次请求接口时，将获取到的数据存储在本地，之后需要时即取即用，减少了大量额外的接口请求。</p>
<hr>
<h1 id="1、三种常用本地存储策略"><a href="#1、三种常用本地存储策略" class="headerlink" title="1、三种常用本地存储策略"></a>1、三种常用本地存储策略</h1><p><em><strong>cookie 属于文档对象模型 DOM 树根节点 document ，而 sessionStorage 和 localStorage 属于浏览器对象模型 BOM 的对象 window 。</strong></em></p>
<p>在 h5 之前，本地存储的主要方式就是 cookie。</p>
<p>sessionStorage 和 localStorage 是 HTML5 Web Storage API 提供的。</p>
<h3 id="cookie"><a href="#cookie" class="headerlink" title="cookie"></a>cookie</h3><ul>
<li>存储大小<ul>
<li>4K，超出会被忽略。</li>
</ul>
</li>
<li>存储形式<ul>
<li>纯文本。这样的字符串无法通过 JSON.parse() 转换为 json 格式的数据，需要通过正则表达式的方式将所需要的值匹配出来，直接使用比较复杂。</li>
</ul>
</li>
<li>存储时间<ul>
<li>可以设置过期时间，expires 选项。</li>
<li>会话期 cookie 浏览器关闭自动清除。</li>
<li>持久性 cookie 设置过期时间，到期后清除。</li>
</ul>
</li>
<li>可以和服务器对话<ul>
<li>在客户端请求服务器的时候，服务器可能会给客户端返回 cookie。</li>
<li>客户端在请求服务器的时候也会在 header 中带上 cookie。</li>
<li>一般检查是否登录是看 cookie。</li>
</ul>
</li>
<li>存储选项<ul>
<li>key&#x2F;value。</li>
<li>expires；cookie的最长有效时间，如果没有表示这是一个会话期cookie。如果想删除一个cookie，只需要把它过期时间设置成过去的时间即可。希望设置过期时间一年：new Date().getTime() + 365 * 24 * 60 * 60 * 1000。</li>
<li>httpOnly：设置了 HttpOnly 属性的 cookie 不能使用 JavaScript读取。</li>
<li>path：字符串，定义cookie的有效路径，默认值 ‘&#x2F;’ 表示当前整个网站都可以访问该 cookie；如果cc.com&#x2F;test&#x2F;index.html 建立了一个cookie，那么在cc.com&#x2F;test&#x2F;目录里的所有页面，以及该目录下面任何子目录里的页面都可以访问这个cookie。</li>
</ul>
</li>
<li>其他<ul>
<li>一次只能设置一个cookie。</li>
</ul>
</li>
</ul>
<h5 id="设置cookie"><a href="#设置cookie" class="headerlink" title="设置cookie"></a>设置cookie</h5><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">document.cookie = &quot;name=yangfeng&quot;;          // 可选的配置</span><br><span class="line">document.cookie = &#x27;test1=hello&#x27;;</span><br><span class="line">document.cookie = &#x27;test2=world&#x27;;</span><br></pre></td></tr></table></figure>

<h5 id="获取cookie"><a href="#获取cookie" class="headerlink" title="获取cookie"></a>获取cookie</h5><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">const allCookies = document.cookie;</span><br></pre></td></tr></table></figure>

<h5 id="删除cookie"><a href="#删除cookie" class="headerlink" title="删除cookie"></a>删除cookie</h5><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">document.cookie = &#x27;test1=hello;expires=Thu, 01-Jan-1970 00:00:01 GMT&#x27;;      // 设置它的expires属性为一个过去的日期</span><br></pre></td></tr></table></figure>

<h3 id="sessionStorage"><a href="#sessionStorage" class="headerlink" title="sessionStorage"></a>sessionStorage</h3><ul>
<li>存储大小<ul>
<li>每个域名限制 5M。</li>
</ul>
</li>
<li>存储形式<ul>
<li>键值对。可以存储数组、数字、对象等可以被序列化为字符串的内容。sessionStorage 中<strong>只能够保存字符串类型</strong>的数据，所以在保存非字符串类型的数据时，一定要先将其转换成字符串，比如图片可以转换成 base64 字符串后保存，对象可使用 JSON.stringify() 转为字符串后存储，甚至可以存储一段 js 脚本。</li>
</ul>
</li>
<li>存储时间<ul>
<li>页面会话期可用，关闭浏览器消失。</li>
<li>页面刷新和恢复也可用。</li>
<li>打开多个相同url的tab页面，会创建各自的session，即不可相互访问。</li>
<li>使用location.href或者window.open来打开另一个同域页面 是可以访问的。<ul>
<li>先操作session再打开才会有。</li>
</ul>
</li>
<li>清除缓存也会消失。</li>
</ul>
</li>
<li>不可以和服务器对话</li>
<li>其他<ul>
<li>可设置多个。</li>
</ul>
</li>
</ul>
<p>sessionStorage 是一个全局对象，数据以键值对的方式进行存储，所以它的使用方式与普通对象非常相似，可以直接通过中括号 sessionStorage[‘key’] 的方式添加和获取数据，也可以通过点语法 sessionStorage.key 的方式进行操作，sessionStorage 也有自己的 api 用于操作数据。</p>
<h5 id="设置sessionStorage"><a href="#设置sessionStorage" class="headerlink" title="设置sessionStorage"></a>设置sessionStorage</h5><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">window.sessionStorage[&#x27;name&#x27;] = &#x27;yangfeng&#x27;;</span><br><span class="line">window.sessionStorage.age = 18;</span><br><span class="line">window.sessionStorage.setItem(&#x27;key&#x27;,&#x27;value&#x27;);</span><br></pre></td></tr></table></figure>

<h5 id="获取sessionStorage"><a href="#获取sessionStorage" class="headerlink" title="获取sessionStorage"></a>获取sessionStorage</h5><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">// 存在返回值，不存在返回 null，需要注意的是如  果使用点语法和中括号，不存在时返回 undefined。</span><br><span class="line">sessionStorage.getItem(&quot;name&quot;);</span><br><span class="line">sessionStorage.name</span><br></pre></td></tr></table></figure>

<h5 id="删除sessionStorage"><a href="#删除sessionStorage" class="headerlink" title="删除sessionStorage"></a>删除sessionStorage</h5><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">// 删除某个sessionStorage</span><br><span class="line">sessionStorage.removeItem(&#x27;key&#x27;);</span><br><span class="line">delete sessionStorage.name;</span><br><span class="line"></span><br><span class="line">// 清除所有数据</span><br><span class="line">sessionStorage.clear();</span><br></pre></td></tr></table></figure>

<blockquote>
<p>刷新页面sessionStorage不会清除，但是打开同域新页面访问不到。</p>
</blockquote>
<h3 id="localStorage"><a href="#localStorage" class="headerlink" title="localStorage"></a>localStorage</h3><ul>
<li>存储大小<ul>
<li>2.5~10M</li>
</ul>
</li>
<li>存储时间<ul>
<li>永久保存</li>
<li>手动清除或者清除缓存</li>
</ul>
</li>
<li>不可以和服务器对话</li>
<li>可以保存任意内容</li>
<li>localStorage满了的情况下仍继续存储并不会覆盖其他的值，而是直接报错(QuotaExceededError) ，当前存储的值会被清空</li>
<li>一个页面操作了 localStorage 同源的页面都可以访问和操作</li>
<li>可以监听同源localStorage的修改（不监听本页面的操作）  <figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">window.addEventListener(&#x27;storage&#x27;, function(e) &#123;</span><br><span class="line">    console.log(&#x27;---&#x27;,e)</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure></li>
</ul>
<h5 id="使用"><a href="#使用" class="headerlink" title="使用"></a>使用</h5><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">window.localStorage.username = &#x27;hehe&#x27;                   // 设置</span><br><span class="line">window.localStorage.setItem(&#x27;username&#x27;, &#x27;hehe&#x27;)         // 设置</span><br><span class="line">window.localStorage.getItem(&#x27;username&#x27;)                 // 读取</span><br><span class="line">window.localStorage.removeItem(&#x27;username&#x27;)              // 删除</span><br><span class="line">window.localStorage.key(1)                              // 读取索引为1的值</span><br><span class="line">window.localStorage.clear()                             // 清除所有</span><br></pre></td></tr></table></figure>

<hr>
<h1 id="2、两种大量数据本地存储策略"><a href="#2、两种大量数据本地存储策略" class="headerlink" title="2、两种大量数据本地存储策略"></a>2、两种大量数据本地存储策略</h1><h3 id="IndexedDB"><a href="#IndexedDB" class="headerlink" title="IndexedDB"></a>IndexedDB</h3><ul>
<li><p>存储大小</p>
<ul>
<li>大于250M</li>
</ul>
</li>
<li><p>存储时间</p>
<ul>
<li>手动更新或删除</li>
</ul>
</li>
<li><p>不可以和服务器对话</p>
</li>
<li><p>创建一个IndexedDB数据库</p>
<ul>
<li>使用window.indexedDB.open(“MyTestDatabase”)创建一个叫MyTestDatabase的数据库，open 函数的结果是一个 IDBDatabase 对象的实例 （接收两个参数）<ul>
<li>第一个参数为数据库名</li>
<li>第二个参数为版本号，默认为1，必须是整数</li>
</ul>
</li>
<li>如果创建的时候有数据库名则直接返回直接返回，没有则新建，新建的时候会触发upgradeneeded事件</li>
</ul>
</li>
<li><p>创建一个对象仓库</p>
<ul>
<li>要创建一个对象仓库必须在upgradeneeded事件中</li>
<li>版本号更新时触发upgradeneeded事件</li>
<li>使用createObjectStore()方法创建一个对象仓库 （接收两个参数）<ul>
<li>第一个参数是对象仓库名，同一数据库中仓库名不能重复</li>
<li>第二个参数，用于指定数据的主键<ul>
<li>是一个对象{keyPath:’xx’,autoIncrement:true}</li>
<li>如果能保证keyPath唯一可以让不设置autoIncrement</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li><p>创建事务（可以存数据了）</p>
<ul>
<li>一个数据库事务通常包含了一个序列的对数据库的读&#x2F;写操作</li>
<li>在操作的时候要么全部操作成功要么全部操作失败</li>
<li>可以使用transaction()来创建一个事务（接收两个参数）<ul>
<li>第一个参数是想要操作的仓库名称</li>
<li>第二个参数是创建的事务模式<ul>
<li>readonly表示制度</li>
<li>readwite表示读写<blockquote>
<p>并非任意的对数据库的操作序列都是数据库事务。数据库事务拥有以下四个特性，习惯上被称之为ACID特性。</p>
</blockquote>
<ul>
<li>原子性（Atomicity）：事务作为一个整体被执行，包含在其中的对数据库的操作要么全部被执行，要么都不执行。</li>
<li>一致性（Consistency）：事务应确保数据库的状态从一个一致状态转变为另一个一致状态。一致状态的含义是数据库中的数据应满足完整性约束</li>
<li>隔离性（Isolation）：多个事务并发执行时，一个事务的执行不应影响其他事务的执行。</li>
<li>持久性（Durability）：已被提交的事务对数据库的修改应该永久保存在数据库中。</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li><p>操作数据</p>
<ul>
<li>add() : 增加数据。接收一个参数，为需要保存到对象仓库中的对象。</li>
<li>put() : 增加或修改数据。接收一个参数，为需要保存到对象仓库中的对象。</li>
<li>get() : 获取数据。接收一个参数，为需要获取数据的主键值。</li>
<li>delete() : 删除数据。接收一个参数，为需要获取数据的主键值。<blockquote>
<p>put 保存数据时，如果该数据的主键在数据库中已经有相同主键的时候，则会修改数据库中对应主键的对象，而使用 add 保存数据，如果该主键已经存在，则保存失败。</p>
</blockquote>
</li>
</ul>
  <figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">const users = &#123;id:&#x27;11&#x27;,name:&#x27;yangf&#x27;,age:18&#125;;</span><br><span class="line">const request = indexedDB.open(&#x27;MyTestDatabase&#x27;, 1);</span><br><span class="line">request.addEventListener(&#x27;upgradeneeded&#x27;, e =&gt; &#123;</span><br><span class="line">    const db = e.target.result;</span><br><span class="line">    // 创建对象仓库</span><br><span class="line">    const  objStore = db.createObjectStore(&#x27;Users&#x27;,&#123; keyPath : &#x27;id&#x27; &#125;);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    // 使用事务的 oncomplete 事件确保在插入数据前对象仓库已经创建完毕</span><br><span class="line">    objStore.transaction.oncomplete = function(event) &#123;</span><br><span class="line">        // 将数据保存到新创建的对象仓库</span><br><span class="line">        const customerObjectStore = db.transaction(&quot;Users&quot;, &quot;readwrite&quot;).objectStore(&quot;Users&quot;);</span><br><span class="line">        customerObjectStore.add(users);</span><br><span class="line">        const reqDelete = customerObjectStore.delete(1)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure></li>
<li><p>索引</p>
<ul>
<li>可以使用存储的对象为当前的存储空间创建索引</li>
<li>这样可以使用索引来查找存储空间中的对象的值</li>
<li>通过在创建索引时设置 unique 标记，可以确保不会有两个具有同样索引 key path 值的对象被储存</li>
<li>使用createIndex()方法创建索引，接收三个参数<ul>
<li>第一个参数name索引名</li>
<li>第二个参数keyPath为存储对象中的一个或多个属性（数组形式）</li>
<li>第三个参数是一个对象参数<ul>
<li>unique: 用来指定索引值是否可以重复,true不能相同,false可以相同</li>
<li>multiEntry： 当keyPath为一个数组时，如果设置multiEntry为true,则会以数组中的每个元素建立一条索引；如果是false,则以整个数组为keyPath值,添加一条索引</li>
</ul>
</li>
</ul>
</li>
<li>使用索引<ul>
<li>使用对象仓库上的index方法,通过传入一个索引名.来拿到一个索引对象</li>
<li>如果索引不唯一，得到的是键值最小的那条数据  <figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">const users = &#123;id:&#x27;11&#x27;,name:&#x27;yangf&#x27;,age:18&#125;;</span><br><span class="line">const request = indexedDB.open(&#x27;MyTestDatabase&#x27;, 1);</span><br><span class="line">request.addEventListener(&#x27;upgradeneeded&#x27;, e =&gt; &#123;</span><br><span class="line">    const db = e.target.result;</span><br><span class="line">    // 创建对象仓库</span><br><span class="line">    const  objStore = db.createObjectStore(&#x27;Users&#x27;,&#123; keyPath : &#x27;id&#x27; &#125;);</span><br><span class="line">    // 创建索引，通过姓名搜索user，可能重复所以unique设置为false</span><br><span class="line">    objStore.createIndex(&quot;name&quot;, &quot;name&quot;, &#123; unique: false &#125;);</span><br><span class="line">    // 使用事务的 oncomplete 事件确保在插入数据前对象仓库已经创建完毕</span><br><span class="line">    objStore.transaction.oncomplete = function(event) &#123;</span><br><span class="line">        // 将数据保存到新创建的对象仓库</span><br><span class="line">        const usersObjectStore = db.transaction(&quot;Users&quot;, &quot;readwrite&quot;).objectStore(&quot;Users&quot;);</span><br><span class="line">        usersObjectStore.add(users);</span><br><span class="line"></span><br><span class="line">        // 使用索引</span><br><span class="line">        var index = usersObjectStore.index(&quot;name&quot;);</span><br><span class="line">        index.get(&quot;yangf&quot;).onsuccess = function(event) &#123;</span><br><span class="line">            console.log(event.target.result);</span><br><span class="line">        &#125;;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure></li>
</ul>
</li>
</ul>
</li>
<li><p>使用游标</p>
<ul>
<li>使用 get() 要求你知道你想要检索哪一个键</li>
<li>想要遍历对象存储空间中的所有值，可以使用游标</li>
<li>使用openCursor() 函数打开游标（接收两个参数）<ul>
<li>第一个参数是范围，可以是一个对象</li>
<li>第二个参数是方向  <figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">// 仅匹配 &quot;yangf&quot;</span><br><span class="line">var singleKeyRange = IDBKeyRange.only(&quot;yangf&quot;);</span><br><span class="line">// 匹配所有超过“Bill”的，包括“Bill”</span><br><span class="line">var lowerBoundKeyRange = IDBKeyRange.lowerBound(&quot;Bill&quot;);</span><br><span class="line">// 匹配所有超过“Bill”的，但不包括“Bill”</span><br><span class="line">var lowerBoundOpenKeyRange = IDBKeyRange.lowerBound(&quot;Bill&quot;, true);</span><br><span class="line">// 匹配所有不超过“Donna”的，但不包括“Donna”</span><br><span class="line">var upperBoundOpenKeyRange = IDBKeyRange.upperBound(&quot;Donna&quot;, true);</span><br><span class="line">// 匹配所有在“Bill”和“Donna”之间的，但不包括“Donna”</span><br><span class="line">var boundKeyRange = IDBKeyRange.bound(&quot;Bill&quot;, &quot;Donna&quot;, false, true);</span><br><span class="line">// 使用其中的一个键范围，把它作为 openCursor()/openKeyCursor 的第一个参数</span><br><span class="line">index.openCursor(boundKeyRange).onsuccess = function(event) &#123;</span><br><span class="line">var cursor = event.target.result;</span><br><span class="line">if (cursor) &#123;</span><br><span class="line">    // 当匹配时进行一些操作</span><br><span class="line">    cursor.continue();</span><br><span class="line">&#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure></li>
</ul>
</li>
</ul>
</li>
<li><p>方向可以传入的参数</p>
  <figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">next : 游标中的数据按主键值升序排列，主键值相等的数据都被读取</span><br><span class="line">nextunique : 游标中的数据按主键值升序排列，主键值相等只读取第一条数据</span><br><span class="line">prev : 游标中的数据按主键值降序排列，主键值相等的数据都被读取</span><br><span class="line">prevunique : 游标中的数据按主键值降序排列，主键值相等只读取第一条数据</span><br><span class="line">// 按照倒叙来排列</span><br><span class="line">index.openCursor(boundKeyRange,&#x27;prev&#x27;).onsuccess = function(event) &#123;</span><br><span class="line">var cursor = event.target.result;</span><br><span class="line">if (cursor) &#123;</span><br><span class="line">    // 当匹配时进行一些操作</span><br><span class="line">    cursor.continue();</span><br><span class="line">&#125;</span><br><span class="line">&#125;;</span><br><span class="line">// 只是想改变遍历的方向，而不想对结果进行筛选，你只需要给第一个参数传入 null</span><br><span class="line">usersObjectStore.openCursor(null, &quot;prev&quot;).onsuccess = function(event) &#123;</span><br><span class="line">var cursor = event.target.result;</span><br><span class="line">if (cursor) &#123;</span><br><span class="line">    // Do something with the entries.</span><br><span class="line">    cursor.continue();</span><br><span class="line">&#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure></li>
<li><p>读取所有的数据</p>
  <figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line">const users = [&#123;id:&#x27;11&#x27;,name:&#x27;yangf&#x27;,age:18&#125;,&#123;id:&#x27;12&#x27;,name:&#x27;yangf&#x27;,age:25&#125;];</span><br><span class="line">const request = indexedDB.open(&#x27;MyTestDatabase&#x27;, 1);</span><br><span class="line">request.addEventListener(&#x27;upgradeneeded&#x27;, e =&gt; &#123;</span><br><span class="line">    const db = e.target.result;</span><br><span class="line">    // 创建对象仓库</span><br><span class="line">    const  objStore = db.createObjectStore(&#x27;Users&#x27;,&#123; keyPath : &#x27;id&#x27; &#125;);</span><br><span class="line">    // 创建索引，通过姓名搜索user，可能重复所以unique设置为false</span><br><span class="line">    objStore.createIndex(&quot;name&quot;, &quot;name&quot;, &#123; unique: false &#125;);</span><br><span class="line">    // 使用事务的 oncomplete 事件确保在插入数据前对象仓库已经创建完毕</span><br><span class="line">    objStore.transaction.oncomplete = function(event) &#123;</span><br><span class="line">        // 将数据保存到新创建的对象仓库</span><br><span class="line">        const usersObjectStore = db.transaction(&quot;Users&quot;, &quot;readwrite&quot;).objectStore(&quot;Users&quot;);</span><br><span class="line">        users.forEach(user=&gt;&#123;</span><br><span class="line">            usersObjectStore.add(user);</span><br><span class="line">        &#125;)</span><br><span class="line">        usersObjectStore.openCursor(null, &quot;prev&quot;).onsuccess = function(event) &#123;</span><br><span class="line">            const cursor = event.target.result;</span><br><span class="line">            if (cursor) &#123;</span><br><span class="line">                // Do something with the entries.</span><br><span class="line">                cursor.continue();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;;</span><br><span class="line">        // 使用索引</span><br><span class="line">        // var index = usersObjectStore.index(&quot;name&quot;);</span><br><span class="line">        // index.get(&quot;yangf&quot;).onsuccess = function(event) &#123;</span><br><span class="line">        //     console.log(event.target.result);</span><br><span class="line">        // &#125;;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure></li>
<li><p>操作IndexedDB的时候，可以进行其他的js操作，是异步的</p>
</li>
<li><p>同源可以相互访问</p>
</li>
</ul>
<h3 id="web-SQL"><a href="#web-SQL" class="headerlink" title="web SQL"></a>web SQL</h3><ul>
<li>存储大小<ul>
<li>自己定义</li>
</ul>
</li>
<li>存储时间<ul>
<li>需要手动清除</li>
</ul>
</li>
</ul>
<p>web SQL相对于indexedDB操作没有那么复杂，但是需要一定的数据库知识<br>使用openDatabase(名称,版本号,描述文本,大小,创建回调)创建一个数据库，返回一个对象<br>使用上面返回的对象可以创建事务，在事务中就可以执行一些操作了，插入、读取等。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">const myDb = openDatabase(&#x27;myDb&#x27;,&#x27;1.0&#x27;,&#x27;test&#x27;,2*1024*1024);</span><br><span class="line">myDb.transaction(function(tx)&#123;</span><br><span class="line">    tx.executeSql(&#x27;CREATE TABLE IF NOT EXISTS LOGS (id unique, log)&#x27;);</span><br><span class="line">    tx.executeSql(&#x27;INSERT INTO LOGS (id, log) VALUES (1, &quot;yangf&quot;)&#x27;);</span><br><span class="line">    tx.executeSql(&#x27;INSERT INTO LOGS (id, log) VALUES (2, &quot;学习&quot;)&#x27;);</span><br><span class="line">&#125;)</span><br><span class="line">myDb.transaction(function (tx) &#123;</span><br><span class="line">    tx.executeSql(&#x27;SELECT * FROM LOGS&#x27;, [], function (tx, results) &#123;</span><br><span class="line">       const len = results.rows.length;</span><br><span class="line">       console.log(&quot;询记录条数: &quot; + len );</span><br><span class="line">    &#125;, null);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>

<hr>
<p><em><strong>参考文献</strong></em></p>
<p><a class="link"   target="_blank" rel="noopener" href="https://zhuanlan.zhihu.com/p/25567678" >知乎 - 前端面试题——三种本地存储策略的区别<i class="fas fa-external-link-alt"></i></a></p>
<p><a class="link"   target="_blank" rel="noopener" href="https://cloud.tencent.com/developer/article/1356670" >腾讯云，开发者社区 - 几种浏览器存储方法及其优缺点<i class="fas fa-external-link-alt"></i></a></p>
<p><a class="link"   target="_blank" rel="noopener" href="https://zhuanlan.zhihu.com/p/647359656" >知乎 - 一文读懂浏览器本地存储：Web Storage<i class="fas fa-external-link-alt"></i></a></p>
<p><a class="link"   target="_blank" rel="noopener" href="https://juejin.cn/post/7044812629197619208" >稀土掘金 - 浏览器存储数据方式<i class="fas fa-external-link-alt"></i></a></p>
<p><a class="link"   target="_blank" rel="noopener" href="https://cloud.tencent.com/developer/article/1356670" >腾讯云 开发者社区 - 几种浏览器存储方法及其优缺点<i class="fas fa-external-link-alt"></i></a></p>

            </div>

            

            
                <ul class="post-tags-box">
                    
                        <li class="tag-item">
                            <a href="/tags/%E6%B5%8F%E8%A7%88%E5%99%A8/">#浏览器</a>&nbsp;
                        </li>
                    
                        <li class="tag-item">
                            <a href="/tags/%E6%95%B0%E6%8D%AE%E5%AD%98%E5%82%A8/">#数据存储</a>&nbsp;
                        </li>
                    
                        <li class="tag-item">
                            <a href="/tags/sessionStorage/">#sessionStorage</a>&nbsp;
                        </li>
                    
                        <li class="tag-item">
                            <a href="/tags/localStorage/">#localStorage</a>&nbsp;
                        </li>
                    
                        <li class="tag-item">
                            <a href="/tags/cookie/">#cookie</a>&nbsp;
                        </li>
                    
                        <li class="tag-item">
                            <a href="/tags/IndexedDB/">#IndexedDB</a>&nbsp;
                        </li>
                    
                        <li class="tag-item">
                            <a href="/tags/web-SQL/">#web SQL</a>&nbsp;
                        </li>
                    
                </ul>
            

            
                <div class="article-nav">
                    
                        <div class="article-prev">
                            <a class="prev"
                               rel="prev"
                               href="/2024/03/26/JavaScript%E5%B8%B8%E7%94%A8%E5%85%AC%E5%85%B1%E6%96%B9%E6%B3%95%E4%B9%8B%E6%97%B6%E9%97%B4%E8%BD%AC%E6%95%B0%E5%AD%97/"
                            >
                            <span class="left arrow-icon flex-center">
                              <i class="fas fa-chevron-left"></i>
                            </span>
                                <span class="title flex-center">
                                <span class="post-nav-title-item">JavaScript常用公共方法之时间转数字</span>
                                <span class="post-nav-item">Prev posts</span>
                            </span>
                            </a>
                        </div>
                    
                    
                        <div class="article-next">
                            <a class="next"
                               rel="next"
                               href="/2023/12/06/JavaScript%E5%B8%B8%E7%94%A8%E5%85%AC%E5%85%B1%E6%96%B9%E6%B3%95%E4%B9%8B%E5%88%A4%E6%96%AD%E5%AD%97%E7%AC%A6%E4%B8%B2%E4%B8%AD%E6%8B%AC%E5%8F%B7%E6%98%AF%E5%90%A6%E6%88%90%E5%AF%B9%E5%87%BA%E7%8E%B0/"
                            >
                            <span class="title flex-center">
                                <span class="post-nav-title-item">JavaScript常用公共方法之判断字符串中括号是否成对出现</span>
                                <span class="post-nav-item">Next posts</span>
                            </span>
                                <span class="right arrow-icon flex-center">
                              <i class="fas fa-chevron-right"></i>
                            </span>
                            </a>
                        </div>
                    
                </div>
            

            
        </div>

        
    </div>
</div>


                
            </div>

        </div>

        <div class="page-main-content-bottom">
            
<footer class="footer">
    <div class="info-container">
        <div class="copyright-info info-item">
            &copy;
            
                <span>2020</span> -
            
            2024
            
                &nbsp;<i class="fas fa-heart icon-animate"></i>
                &nbsp;<a href="/">aaton</a>
            
        </div>
        
            <script async 
                    src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
            <div class="website-count info-item">
                
                    Visitor Count&nbsp;<span id="busuanzi_value_site_uv"></span>&ensp;
                
                
                    Totalview&nbsp;<span id="busuanzi_value_site_pv"></span>
                
            </div>
        
        <div class="theme-info info-item">
            Powered by <a target="_blank" href="https://hexo.io">Hexo</a>&nbsp;|&nbsp;Theme&nbsp;<a class="theme-version" target="_blank" href="https://github.com/XPoet/hexo-theme-keep">Keep v3.6.1</a>
        </div>
        
        
    </div>
</footer>

        </div>
    </div>

    
        <div class="post-tools">
            <div class="post-tools-container">
    <ul class="tools-list">
        <!-- TOC aside toggle -->
        

        <!-- go comment -->
        
    </ul>
</div>

        </div>
    

    <div class="right-bottom-side-tools">
        <div class="side-tools-container">
    <ul class="side-tools-list">
        <li class="tools-item tool-font-adjust-plus flex-center">
            <i class="fas fa-search-plus"></i>
        </li>

        <li class="tools-item tool-font-adjust-minus flex-center">
            <i class="fas fa-search-minus"></i>
        </li>

        <li class="tools-item tool-dark-light-toggle flex-center">
            <i class="fas fa-moon"></i>
        </li>

        <!-- rss -->
        

        
            <li class="tools-item tool-scroll-to-top flex-center">
                <i class="fas fa-arrow-up"></i>
            </li>
        

        <li class="tools-item tool-scroll-to-bottom flex-center">
            <i class="fas fa-arrow-down"></i>
        </li>
    </ul>

    <ul class="exposed-tools-list">
        <li class="tools-item tool-toggle-show flex-center">
            <i class="fas fa-cog fa-spin"></i>
        </li>
        
    </ul>
</div>

    </div>

    <div class="zoom-in-image-mask">
    <img class="zoom-in-image">
</div>


    

</main>




<script src="/js/utils.js"></script>

<script src="/js/main.js"></script>

<script src="/js/header-shrink.js"></script>

<script src="/js/back2top.js"></script>

<script src="/js/dark-light-toggle.js"></script>







    
<script src="/js/code-block.js"></script>





<div class="post-scripts">
    
        
<script src="/js/post-helper.js"></script>

        
        
    
</div>



</body>
</html>
